/**
 * 模拟控件在页面上掉落的动画特效
 *
 * $(selector).fake (opts);
 * selector - 选择器，只有具备keyup事件的控件才能使用
 * 其中合法的opts属性有：
 *   - container             selector        需要旋转的对象
 *   - matches               function        function (value:String) : Boolean
 *                                           该函数返回true时将触发特效
 */
(function ($) {
    if ($.fn.fake) return;

    var T = 50, dT = T / 1000.0, H = $(window).height ();

    function onKeyUp () {
        var self = $(this), settings = self.data ('settings'), holder = self.data ('holder');
        if (!holder) {
            holder = {deg:0};
            self.data ('holder', holder);
        }
        if (('matches' in settings) && typeof (settings['matches']) === 'function') {
            if (settings ['matches'].apply (this, [this.value])) {
                action.apply (this);
            } else {
                if (holder.fake) {
                    holder.fake.remove ();
                    delete holder.fake;

                    if (holder.parent)
                        holder.parent.css('visibility', 'visible');
                }
            }
        }
    }

    function action () {
        var self = $(this), settings = self.data ('settings'), holder = self.data ('holder'),
            div = self.closest ($(settings ['container'])), pos;
        if (!div) {
            return;
        }
        holder.parent = div;
        pos = div.offset ();
        if (!holder.fake && !holder.shadow) {
            holder.shadow = clone (div);
        }
        div.css ('visibility', 'hidden');

        if (!holder.fake) {
            holder.fake = $('<div id="fake-container" class="floating-box"/>');
            holder.fake.append(clone(div).css({visibility: 'hidden', float: 'left'}).attr('id', '_')).append(holder.shadow);
            holder.fake.addClass('floating-box').css({
                top: pos.top, left: pos.left, width: 2 * div.width(), height: div.height(),
                'margin-left': -div.width()
            }).appendTo($(document.body));
            rotate (holder, 90, false, true);
        }
    }

    function rotate (holder, DEG, limit, falling, logging) {
        var t = 0, alpha, box, x0, y0, x1, y1, dx, dy;
        holder.handler = setInterval(function () {
            if (holder.deg >= DEG) {
                if (limit) {
                    holder.fake.css({transform: 'rotate(' + DEG + 'deg)'});
                }
                if (holder.handler) {
                    box = {x:holder.fake.offset().left, y:holder.fake.offset ().top, w:holder.fake.width(), h:holder.fake.height()};
                    if (logging)
                        console.log ('--------- box = ', box);
                    clearInterval (holder.handler);
                    delete holder.handler;

                    //////////////////////////////////////////////
                    if (falling) {
                        fallon (holder);
                    } else {
                        holder.fake.animate ({opacity:0}, 'slow');
                    }
                }
            } else {
                box = {
                    x:parseFloat (holder.fake.css ('left')),
                    y:parseFloat (holder.fake.css ('top')),
                    w:holder.fake.width(), h:holder.fake.height()
                };
                alpha = Math.PI - holder.deg * Math.PI / 180;
                if (logging) {
                    console.log ('alpha = ' + alpha);
                }
                x0 = box.w * Math.cos (alpha) / 2;
                y0 = box.w * Math.sin (alpha) / 2;
                t += dT;
                holder.deg += 5 * t * t;
                alpha = Math.PI - holder.deg * Math.PI / 180;
                x1 = box.w * Math.cos (alpha) / 2;
                y1 = box.w * Math.sin (alpha) / 2;
                dx = x1 - x0;
                dy = y1 - y0;
                if (logging) {
                    console.log ('box = ', box);
                    console.log ('alpha = ' + alpha);
                    console.log ('x0 = ' + x0 + ', y0 = ' + y0);
                    console.log ('x1 = ' + x1 + ', y1 = ' + y1);
                    console.log ('dx = ' + dx + ', dy = ' + dy);
                }
                var opt = {transform: 'rotate(' + holder.deg + 'deg)'};
                if (!falling) {
                    opt.left = box.x + Math.abs (dx);
                    opt.top  = box.y + Math.abs (dy);
                }
                if (logging)
                    console.log (opt);
                holder.fake.css(opt);
            }
        }, 17);
    }

    function fallon (holder) {
        if (!holder.fake || !holder.shadow) {
            return;
        }

        var pos = holder.fake.offset (), box = {x:pos.left, y:pos.top, w:holder.fake.width(), h:holder.fake.height()}, dh;
        dh = H - box.h - box.y;
        holder.fake.animate ({top:'+=' + dh + 'px'}, function () {
            rotate (holder, 180, true, false);
        });
    }

    function clone (src) {
        var target = $(src).clone ();
        target.css ({width:$(src).width(), height:$(src).height()});
        target.find ('input').removeAttr ('id').removeAttr ('placeholder');
        return target;
    }

    $.fn.fake = function (options) {
        return this.each (function () {
            var self = $(this).data ('settings', $.extend ({}, options || {}));
            if (self.is ('input')) {
                self.on ('keyup', onKeyUp);
            }
        });
    };

    $ (function () {
        var style = $('style#fake-style');
        if (!style.length) {
            $('<style id="fake-style" type="text/css" rel="stylesheet"/>')
                .text (".floating-box {position: absolute; z-index: 3000;}")
                .appendTo ($('head'));
        }
    })
}) (jQuery);